/*
package com.dkd.sbtz.service.impl;

import com.dkd.common.core.domain.TreeSelect;
import com.dkd.common.core.domain.entity.SysDept;
import com.dkd.common.exception.ServiceException;
import com.dkd.common.utils.DateUtils;
import com.dkd.common.utils.StringUtils;
import com.dkd.sbtz.domain.AssetNodeUsage;
import com.dkd.sbtz.domain.Sbtz;
import com.dkd.sbtz.domain.vo.*;
import com.dkd.sbtz.mapper.SbtypeMapper;
import com.dkd.sbtz.mapper.SbtzMapper;
import com.dkd.sbtz.mapper.SpareMapper;
import com.dkd.sbtz.service.ISbtzService;
import com.dkd.system.mapper.SysDeptMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

*/
/**
 * 设备台账Service业务层处理
 *
 * @author xzj
 * @date 2025-09-02
 *//*

@Slf4j
@Service
public class SbtzServiceImplOld implements ISbtzService
{
    @Autowired
    private SbtzMapper sbtzMapper;

    @Autowired
    private SpareMapper spareMapper;

    @Autowired
    private SbtypeMapper  assetTypeEdgeMapper;

    @Autowired
    private SysDeptMapper deptMapper;



    */
/**
     * 查询设备台账
     *
     * @param id 设备台账主键
     * @return 设备台账
     *//*

    @Override
    public Sbtz selectSbtzById(Long id)
    {
        return sbtzMapper.selectSbtzById(id);
    }

    */
/**
     * 查询设备台账列表
     *
     * @param sbtz 设备台账
     * @return 设备台账
     *//*

    @Override
    public List<Sbtz> selectSbtzList(Sbtz sbtz)
    {
        return sbtzMapper.selectSbtzList(sbtz);
    }

    */
/**
     * 新增设备台账
     *
     * @param sbtz 设备台账
     * @return 结果
     *//*

    @Override
    public int insertSbtz(Sbtz sbtz)
    {
        sbtz.setCreateTime(DateUtils.getNowDate());
        return sbtzMapper.insertSbtz(sbtz);
    }

    */
/**
     * 修改设备台账
     *
     * @param sbtz 设备台账
     * @return 结果
     *//*

    @Override
    public int updateSbtz(Sbtz sbtz)
    {
        sbtz.setUpdateTime(DateUtils.getNowDate());
        return sbtzMapper.updateSbtz(sbtz);
    }

    */
/**
     * 批量删除设备台账
     *
     * @param ids 需要删除的设备台账主键
     * @return 结果
     *//*

    @Override
    public int deleteSbtzByIds(Long[] ids)
    {
        return sbtzMapper.deleteSbtzByIds(ids);
    }

    */
/**
     * 删除设备台账信息
     *
     * @param id 设备台账主键
     * @return 结果
     *//*

    @Override
    public int deleteSbtzById(Long id)
    {
        return sbtzMapper.deleteSbtzById(id);
    }

    // Jackson：用于把对象转成 JSON
    private static final com.fasterxml.jackson.databind.ObjectMapper M = new com.fasterxml.jackson.databind.ObjectMapper();


    // 计算“当前要插入子节点”的 ancestors（不含自己）
    private static String buildAncestors(String parentAncestors, Long parentId) {
        if (parentId == null || parentId == 0L) return "";           // 根的子：无祖先
        if (StringUtils.isBlank(parentAncestors)) return String.valueOf(parentId);
        return parentAncestors + "," + parentId;
    }


    */
/*
        完成前端新增层级关系的代码
    *//*

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> createRoute(RouteCreateDTO dto, String operUser) {

        if (dto == null || dto.getLayers() == null || dto.getLayers().isEmpty()) {
            throw new ServiceException("没有需要创建的层");
        }

        Long parentId = (dto.getStartParentId() == null ? 0L : dto.getStartParentId());
        boolean reuse = Boolean.TRUE.equals(dto.getReuseCode());

        // === 上下文：父节点的“类型/层级/路径/祖先链” ===
        String parentType;        // ← 新增：父节点类型
        String parentPath = "/";
        String parentAncestors = "";
        int parentLevel = 0;

        if (parentId != 0L) {
            Sbtz parent = sbtzMapper.getById(parentId);
            if (parent == null) throw new ServiceException("父节点不存在：" + parentId);
            parentType = parent.getNodeType();                             // ← 父类型
            parentPath = StringUtils.defaultIfBlank(parent.getPath(), "/");
            parentAncestors = StringUtils.defaultString(parent.getAncestors());
            parentLevel = parent.getLevel();
        } else {
            parentType = "ROOT";                                           // ← 约定根类型
        }

        List<Long> createdIds = new ArrayList<>();
        List<Long> ancestorChain = new ArrayList<>();
        if (parentId != 0L) ancestorChain.add(parentId);

        for (RouteCreateDTO.Layer layer : dto.getLayers()) {
            if (StringUtils.isBlank(layer.getNodeType()) || StringUtils.isBlank(layer.getName())) {
                throw new ServiceException("类型与名称为必填");
            }
            String childType = layer.getNodeType().trim().toUpperCase();

            // === 1) 父子类型约束校验 ===
            assertEdgeAllowed(parentType, childType);

            // === 2) （可选）复用：若允许复用且 code 命中同父同类型，则直接把 parentId 切到命中节点继续往下 ===
            if (reuse && StringUtils.isNotBlank(layer.getCode())) {
                Sbtz existed = sbtzMapper.findOneByParentTypeCode(parentId, childType, layer.getCode().trim());
                if (existed != null) {
                    // 切换上下文到命中节点，继续处理下一层
                    parentId = existed.getId();
                    parentType = existed.getNodeType();
                    parentLevel = existed.getLevel();
                    String fullPath = safePath(parentPath) + parentId + "/";
                    parentPath = fullPath;
                    parentAncestors = appendAncestor(existed.getAncestors(), parentId);
                    ancestorChain.add(parentId);
                    continue;
                }
            }

            // === 3) 创建节点（你原有逻辑） ===
            String finalCode = ensureUniqueCodeCreate(StringUtils.trim(layer.getCode()), reuse);
            String specification = layer.getSpecification().trim();
            String model = layer.getModel().trim();
            String material = layer.getMaterial().trim();
            String power = layer.getPower().trim();
            String brand = layer.getBrand().trim();
            String manufacturer = layer.getManufacturer().trim();
            Integer isSpecial = layer.getIsSpecial();
            Long spareId = layer.getSpareId();
            Integer deptId = layer.getDeptId();
            Integer status =layer.getStatus();

            Sbtz node = new Sbtz();
            node.setName(layer.getName());
            node.setNodeType(childType);
            node.setCode(finalCode);
            node.setParentId(parentId);
            node.setLevel(parentLevel + 1);
            node.setAncestors(joinAncestors(parentAncestors, ancestorChain)); // 不含自身
            node.setPath(parentPath);
            node.setOrderNum(0);
            node.setStatus(status);
            node.setDelFlag(0);
            node.setRemark(layer.getRemark());
            node.setCreateBy(operUser);
            node.setUpdateBy(operUser);
            node.setSpecification(specification);
            node.setModel(model);
            node.setMaterial(material);
            node.setPower(power);
            node.setBrand(brand);
            node.setManufacturer(manufacturer);
            node.setIsSpecial(isSpecial);
            node.setDeptId(deptId);
            node.setSpareId(spareId);
//            node.setCreateTime(
//                    java.sql.Timestamp.valueOf(LocalDateTime.now())
//            );
            node.setCreateTime(new Date());




            // 1) 计算正确的 ancestors（不含自己）
            String ancestorsForChild = buildAncestors(parentAncestors, parentId);
            node.setAncestors(ancestorsForChild);

            sbtzMapper.insertNode(node);
            Long id = node.getId();
            String fullPath = safePath(parentPath) + id + "/";
            sbtzMapper.updatePath(id, fullPath);

            // 闭包表/备件关联（保持你原有逻辑）
            // 闭包表：祖先→新节点 + 自反
            // ★ 关键：用插入-选择把父的所有祖先写给新节点
            sbtzMapper.insertClosureForNewNode(parentId, id);

            // 备件关联：仅当 spareId 有值；qty_need 走表默认 1.00；is_primary 固定 0
            if (layer.getSpareId() != null && layer.getSpareId() > 0) {
                spareMapper.insertNodeSpareLinks(id, layer.getSpareIds(), operUser, layer.getRemark());
            }

            changeUsage(id, status, (long)deptId, operUser,"");


            // === 4) 刷新“下一轮”的父上下文 ===
            parentId = id;
            parentType = childType;                 // ← 父类型变成刚建的子类型
            parentLevel = node.getLevel();
            parentPath = fullPath;
//            parentAncestors = appendAncestor(node.getAncestors(), id);
            parentAncestors = ancestorsForChild;
//            ancestorChain.add(id);
            createdIds.add(id);
        }
        return createdIds;
    }


    public void changeUsage(Long assetId, Integer status, Long deptId, String operator,String reason) {
        if (assetId == null || status == null) {
            throw new ServiceException("assetId/status 不能为空");
        }
        if (status < 0 || status > 4) {
            throw new ServiceException("非法的设备状态");
        }

        final LocalDateTime now = LocalDateTime.now();
        AssetNodeUsage open = sbtzMapper.selectOpenByAsset(assetId); // 当前未闭合记录（可能为 null）

        if (status == 0) { // 使用：必须选部门
            if (deptId == null || deptId <= 0) {
                throw new ServiceException("启用状态必须选择部门");
            }
            SysDept dept = deptMapper.selectDeptById(deptId);
            if (dept == null || "2".equals(dept.getStatus())) {
                throw new ServiceException("部门不存在或已停用");
            }

            // 幂等：如果已是“使用中 & 部门相同”，直接返回
            if (open != null && open.getStatus() == 0 && deptId.equals(open.getDeptId())) {
                return;
            }

            // 关闭旧打开记录（无论旧记录是什么状态）
            if (open != null) {
                sbtzMapper.closeOpenByAsset(assetId, now);
            }

            // 插入新的“使用”记录
            AssetNodeUsage row = new AssetNodeUsage();
            row.setAssetId(assetId);
            row.setStatus(status);
            row.setDeptId(deptId);
            row.setDeptName(dept.getDeptName() == null ? "" : dept.getDeptName());
            row.setStartTs(now);
            row.setEndTs(null);
            row.setReason(reason);
            row.setCreatedBy(operator);

            // 唯一约束下可能出现并发/重复，采用 insertIgnore 风格保证不抛错
            sbtzMapper.insertIgnore(row);
            return;
        }

        // 非使用状态：部门必须为空（保存为 0 / ""）
        Long deptIdNorm = 0L;
        String deptNameNorm = "";

        // 幂等：如果已有打开记录且状态相同且 dept=0，则直接返回
        if (open != null && open.getStatus() == status &&
                (open.getDeptId() == null || open.getDeptId() == 0L)) {
            return;
        }

        // 关闭旧打开记录
        if (open != null) {
            sbtzMapper.closeOpenByAsset(assetId, now);
        }

        // 插入新的“非使用”记录
        AssetNodeUsage row = new AssetNodeUsage();
        row.setAssetId(assetId);
        row.setStatus(status);
        row.setDeptId(deptIdNorm);
        row.setDeptName(deptNameNorm);
        row.setStartTs(now);
        row.setEndTs(null);
        row.setReason(reason == null ? "" : reason);
        row.setCreatedBy(operator);

        sbtzMapper.insertIgnore(row);
    }



    private String ensureUniqueCodeCreate(String code, boolean reuse) {
        if (StringUtils.isBlank(code)) return null; // 允许无编码
        if (sbtzMapper.existsCode(code) == 0) return code;
        if (!reuse) throw new ServiceException("编码已存在：" + code);
        String base = code; int i = 1; String candidate = code;
        while (sbtzMapper.existsCode(candidate) > 0) candidate = base + "-" + i++;
        return candidate;
    }

    // 校验方法（属于该 Service）
    private void assertEdgeAllowed(String parentType, String childType) {
        // 例如：ROOT -> SYSTEM 要在约束表里预置一条
        if (assetTypeEdgeMapper.existsEdge(parentType, childType) <= 0) {
            throw new ServiceException("不允许的父子类型：" + parentType + " → " + childType);
        }
    }




    private String joinAncestors(String parentAncestors, List<Long> chain) {
        if (chain == null || chain.isEmpty()) return StringUtils.defaultString(parentAncestors);
        StringBuilder sb = new StringBuilder(StringUtils.defaultString(parentAncestors));
        for (Long id : chain) {
            if (sb.length() > 0 && sb.charAt(sb.length()-1) != ',') sb.append(',');
            sb.append(id);
        }
        return sb.toString();
    }

    private String appendAncestor(String oldAnc, Long self) {
        return StringUtils.isBlank(oldAnc) ? String.valueOf(self) : oldAnc + "," + self;
    }

    private String safePath(String p) { return StringUtils.defaultIfBlank(p, "/"); }
    */
/*
        完成前端新增层级关系的代码
    *//*




    private String toJson(Object o) {
        try { return M.writerWithDefaultPrettyPrinter().writeValueAsString(o); }
        catch (Exception e) { return String.valueOf(o); }
    }
    private int size(RouteCreateDTO dto){ return dto==null||dto.getLayers()==null?0:dto.getLayers().size(); }


    */
/*懒加载父节点选择器*//*

    @Override
//    public List<NodeOptionVO> children(Long parentId) {
//        Long pid = (parentId == null ? 0L : parentId);
//        List<Sbtz> list = sbtzMapper.selectByParentId(pid);
//        List<NodeOptionVO> out = new ArrayList<>(list.size());
//        for (Sbtz n : list) {
//            boolean hasChild = sbtzMapper.existsChild(n.getId()) > 0;
//            String label = n.getName() + (n.getCode() != null ? "（" + n.getCode() + "）" : "");
//            out.add(new NodeOptionVO(n.getId(), label, !hasChild)); // leaf = !hasChild
//        }
//        return out;
//    }
    public List<NodeOptionVO> children(Long parentId) {
        Long pid = (parentId == null ? 0L : parentId);
        List<Sbtz> list = sbtzMapper.selectByParentId(pid);
        List<NodeOptionVO> out = new ArrayList<>(list.size());
        for (Sbtz n : list) {
            boolean hasChild = sbtzMapper.existsChild(n.getId()) > 0;
            String label = n.getName() + (n.getCode() != null ? "（" + n.getCode() + "）" : "");
            // ✨ 把 nodeType 一起返回；懒加载需要的是 leaf 字段（无子=leaf=true）
            out.add(new NodeOptionVO(
                    n.getId(),
                    label,
                    !hasChild,           // leaf
                    n.getNodeType()      // ✨ nodeType
            ));
        }
        return out;
    }



    private static <T> T nvl(T a, T b) { return a != null ? a : b; }


    */
/*查询数据*//*

    @Override
    @Transactional(readOnly = true)
    public List<AssetNodeListVO> selectSbtzListVO(Sbtz sbtz) {
        return sbtzMapper.selectSbtzListVO(sbtz);
    }

    */
/*查询数据*//*

    @Override
    @Transactional(readOnly = true)
    public List<AssetNodeListVO> selectSearchData(Sbtz sbtz) {
        return sbtzMapper.selectSearchData(sbtz);
    }


    */
/*导出数据*//*

    @Override
    @Transactional(readOnly = true)
    public List<AssetNodeExportVO> selectForExport(Sbtz sbtz) {
        return sbtzMapper.selectForExport(sbtz);
    }


    @Override
    @Transactional(readOnly = true)
    public List<ExportWithParentVO> selectChainRowsForExport(Sbtz sbtz) {
        return sbtzMapper.selectChainRowsForExport(sbtz);
    }

    */
/**
     * 删除节点及其全部子孙节点（硬删除）
     * @return 实际删除的记录数
     *//*

//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public int deleteSubtree(Long nodeId, String operUser) {
//        // 可选：行级锁，避免并发重家/删除冲突
//        Sbtz cur = sbtzMapper.lockById(nodeId); // SELECT ... FOR UPDATE
//        if (cur == null) throw new ServiceException("节点不存在: " + nodeId);
//
//        // 查询所有子孙
//        List<Long> descendantIds = sbtzMapper.selectDescendantIds(nodeId);
//
//        int affected = 0;
//        if (!descendantIds.isEmpty()) {
//            affected += sbtzMapper.deleteNodesByIds(descendantIds);
//        }
//        affected += sbtzMapper.deleteNodeById(nodeId);
//
//        // 可选：记录审计日志
//        // auditLog.info("deleteSubtree", operUser, nodeId, descendantIds);
//
//        return affected;
//    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteSubtree(Long nodeId, String operUser) {
        // 可选：行级锁，避免并发移动/删除冲突
        Sbtz cur = sbtzMapper.lockById(nodeId);
        if (cur == null) throw new ServiceException("节点不存在: " + nodeId);

        int affected = 0;

        // 1) 删除全部子孙节点（不含自己）
        //    由于你已对 asset_node_rel、asset_node_spare 配了 ON DELETE CASCADE，
        //    这些子孙相关的闭包行/备件行会自动被清理。
        affected += sbtzMapper.deleteChildrenByAncestor(nodeId);

        // 2) 删除自己
        affected += sbtzMapper.deleteNodeById(nodeId);

        // 可选：记录审计日志
        // auditLog.info("deleteSubtree", operUser, nodeId, affected);

        return affected;
    }


    public static <T, R> R mapOrElse(T obj, java.util.function.Function<T, R> fn, R defVal) {
        if (obj == null) return defVal;
        R v = fn.apply(obj);
        return v != null ? v : defVal;
    }

    */
/*修改节点所属关系*//*

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long rehomeByRecreate(RehomeByRecreateDTO req, String operUser) {
        Long nodeId      = req.getNodeId();
        Long newParentId = (req.getNewParentId() == null ? 0L : req.getNewParentId());

        // 0) 当前节点 & 现父
        Sbtz cur = sbtzMapper.getById(nodeId);
        if (cur == null) throw new ServiceException("节点不存在: " + nodeId);

        Long oldParentId = (cur.getParentId() == null ? 0L : cur.getParentId());
        boolean moving = !Objects.equals(newParentId, oldParentId); // 是否真的在搬家

        // 1) 取新父（搬家时才需要），并做父子类型校验
        String parentType = "ROOT";
        Sbtz newParent = null;
        if (newParentId != 0L) {
            newParent = sbtzMapper.getById(newParentId);
            if (newParent == null) throw new ServiceException("新父节点不存在: " + newParentId);
            parentType = newParent.getNodeType();
        }

        RehomeByRecreateDTO.OverrideLayer ov = req.getOverride();
        String newType = (ov != null && StringUtils.isNotBlank(ov.getNodeType()))
                ? ov.getNodeType().trim()
                : cur.getNodeType();

        // 仅当“搬家”或者“类型变了”时才做边约束校验
        if (moving || !Objects.equals(newType, cur.getNodeType())) {
            if (assetTypeEdgeMapper.existsEdge(parentType, newType) <= 0) {
                throw new ServiceException("不允许的父子类型: " + parentType + " → " + newType);
            }
        }


        String specification = (ov != null && ov.getSpecification() != null) ? ov.getSpecification().trim() : "";
        String model = (ov != null && ov.getModel() != null) ? ov.getModel().trim() : "";
        String material = (ov != null && ov.getMaterial() != null) ? ov.getMaterial().trim() : "";
        String power = (ov != null && ov.getPower() != null) ? ov.getPower().trim() : "";
        String brand = (ov != null && ov.getBrand() != null) ? ov.getBrand().trim() : "";
        String manufacturer = (ov != null && ov.getManufacturer() != null) ? ov.getManufacturer().trim() : "";
//        Integer isSpecial = (ov != null && ov.getIsSpecial() != null) ? ov.getIsSpecial() : 0;
        Integer isSpecial = mapOrElse(ov, x -> x.getIsSpecial(), 0);
        Integer deptId   = (ov != null && ov.getDeptId() != null) ? ov.getDeptId() : 0;
        Long spareId   = (ov != null && ov.getSpareId() != null) ? ov.getSpareId() : 0;
        Integer status = mapOrElse(ov, x -> x.getStatus(), 0);

        SbtzPatchReq upData = new SbtzPatchReq();
        upData.setId(nodeId);
        upData.setUpdateBy(operUser);

        upData.setSpecification(specification);
        upData.setModel(model);
        upData.setMaterial(material);
        upData.setPower(power);
        upData.setBrand(brand);
        upData.setManufacturer(manufacturer);
        upData.setIsSpecial(isSpecial);
        upData.setDeptId(deptId);
        upData.setSpareId(spareId);
        upData.setStatus(status);
        upData.setUpdateTime(new Date());

        changeUsage(nodeId, status, (long)deptId, operUser,"");
        // 2) 若不搬家：仅更新自身字段 & 备件，直接返回
        if (!moving) {
            String newName = (ov != null && StringUtils.isNotBlank(ov.getName()))
                    ? ov.getName().trim() : cur.getName();

            String newCode;
            if (Boolean.TRUE.equals(req.getKeepCode())) {
                newCode = (ov != null && StringUtils.isNotBlank(ov.getCode()))
                        ? ensureUniqueCode(ov.getCode().trim(), true, nodeId) // 排除自身
                        : cur.getCode();
            } else {
                String wished = (ov == null ? null : StringUtils.trimToNull(ov.getCode()));
                newCode = (wished == null) ? null : ensureUniqueCode(wished, false, nodeId);
            }

            String newRemark = (ov != null && ov.getRemark() != null) ? ov.getRemark() : cur.getRemark();

            upData.setName(newName);
            upData.setCode(newCode);
            upData.setNodeType(newType);
            upData.setRemark(newRemark);
            sbtzMapper.updateByIdSelective(upData);

            // 先清再挂（未选择/0 => 清空；>0 => 重挂）
            Long sid = (ov == null ? null : ov.getSpareId());
            sbtzMapper.deleteNodeSpareLinks(nodeId);
            if (sid != null && sid > 0) {
                sbtzMapper.insertNodeSpareLink(nodeId, sid, 0, newRemark);
            }

            return nodeId;
        }

        // 3) 真正搬家：防环
        if (newParentId.equals(nodeId)) throw new ServiceException("新父节点不能是自己");
//        if (sbtzMapper.existsAncestor(newParentId, nodeId) > 0) {
//            throw new ServiceException("新父在当前子树中，禁止移动");
//        }

        // 4) 删子孙（不含自己）+ 更新自身字段
        sbtzMapper.deleteChildrenByAncestor(nodeId);

        String newName = (ov != null && StringUtils.isNotBlank(ov.getName()))
                ? ov.getName().trim() : cur.getName();

        String newCode;
        if (Boolean.TRUE.equals(req.getKeepCode())) {
            newCode = (ov != null && StringUtils.isNotBlank(ov.getCode()))
                    ? ensureUniqueCode(ov.getCode().trim(), true, nodeId)
                    : cur.getCode();
        } else {
            String wished = (ov == null ? null : StringUtils.trimToNull(ov.getCode()));
            newCode = (wished == null) ? null : ensureUniqueCode(wished, false, nodeId);
        }

        String newRemark = (ov != null && ov.getRemark() != null) ? ov.getRemark() : cur.getRemark();

        upData.setName(newName);
        upData.setCode(newCode);
        upData.setNodeType(newType);
        upData.setRemark(newRemark);
        sbtzMapper.updateByIdSelective(upData);
//        sbtzMapper.updateRootFields(nodeId, newType, newName, newCode, newRemark, operUser);

        // 仅当本次显式传了 spareId 才变更（否则保持原样）
        if (ov != null && ov.getSpareId() != null) {
            sbtzMapper.deleteNodeSpareLinks(nodeId);
            if (ov.getSpareId() > 0) {
                sbtzMapper.insertNodeSpareLink(nodeId, ov.getSpareId(), 0, newRemark);
            }
        }

        // 5) 闭包：剪旧外连 -> 接新外连
        sbtzMapper.deleteSelfExternalClosure(nodeId);
        sbtzMapper.insertClosureForExistingNode(newParentId, nodeId);

        // 6) 元数据
        String ancestors = (newParentId == 0L) ? ""
                : (StringUtils.isBlank(newParent.getAncestors())
                ? String.valueOf(newParentId)
                : newParent.getAncestors() + "," + newParentId);

        String path  = (newParentId == 0L) ? ("/" + nodeId + "/") : (newParent.getPath() + nodeId + "/");
        int    level = (newParentId == 0L) ? 1 : newParent.getLevel() + 1;

        sbtzMapper.updateSelfMetaAfterRehome(nodeId, newParentId, ancestors, path, level, operUser);
        return nodeId;
    }

    */
/** 保障编码唯一；allowReuse=true 允许本记录保留原码（排除自身） *//*

    private String ensureUniqueCode(String code, boolean allowReuse, Long selfId) {
        if (StringUtils.isBlank(code)) return null;
        int cnt = sbtzMapper.countCodeExcludeSelf(code, selfId);
        if (cnt == 0) return code;
        if (!allowReuse) throw new ServiceException("编码已存在：" + code);
        String base = code; int i = 1; String c = code;
        while (sbtzMapper.countCodeExcludeSelf(c, selfId) > 0) c = base + "-" + i++;
        return c;
    }


    */
/**
     * 仅删除子树（不含自身），需要时也可以暴露给前端
     *//*

    @Transactional(rollbackFor = Exception.class)
    public int deleteChildren(Long nodeId, String operUser) {
        Sbtz cur = sbtzMapper.lockById(nodeId);
        if (cur == null) throw new ServiceException("节点不存在: " + nodeId);

        List<Long> descendantIds = sbtzMapper.selectDescendantIds(nodeId);
        if (descendantIds.isEmpty()) return 0;
        // 这里如果 selectDescendantIds 返回的是“所有后代”，会包含多层级，满足需要
        int affected = sbtzMapper.deleteNodesByIds(descendantIds);

        // auditLog.info("deleteChildren", operUser, nodeId, descendantIds);
        return affected;
    }


    */
/*返回类似部门一样的数列表选择*//*

    @Override
    public List<TreeSelect> selectAssetTreeList(Sbtz sbtz) {
        // 这里不要 startPage()
        List<Sbtz> list = sbtzMapper.selectAssetTreeList(sbtz);
        List<Sbtz> tree = buildSbtzTree(list);
        return tree.stream().map(this::toTreeSelect).collect(Collectors.toList());
    }

    */
/** 把平铺列表组树：O(n)，并初始化 children，最后做统一排序 *//*

    private List<Sbtz> buildSbtzTree(List<Sbtz> list) {
        if (list == null || list.isEmpty()) return Collections.emptyList();

        // 先放进 map，并初始化 children，避免 NPE
        Map<Long, Sbtz> map = new HashMap<>(list.size() * 4 / 3 + 1);
        for (Sbtz n : list) {
            n.setChildren(new ArrayList<>());  // 保证非 null
            map.put(n.getId(), n);
        }

        List<Sbtz> roots = new ArrayList<>();
        for (Sbtz n : list) {
            Long pid = n.getParentId() == null ? 0L : n.getParentId();
            Sbtz parent = map.get(pid);
            if (parent == null) {
                // 没有父或父不在当前集合中 → 视为根
                roots.add(n);
            } else {
                parent.getChildren().add(n);
            }
        }

        // 统一排序：orderNum -> name（按需修改）
        Comparator<Sbtz> cmp = Comparator
                .comparing((Sbtz x) -> x.getOrderNum() == null ? 0 : x.getOrderNum())
                .thenComparing(x -> x.getName() == null ? "" : x.getName());
        sortRecursively(roots, cmp);

        return roots;
    }

    private void sortRecursively(List<Sbtz> nodes, Comparator<Sbtz> cmp) {
        nodes.sort(cmp);
        for (Sbtz n : nodes) {
            if (n.getChildren() != null && !n.getChildren().isEmpty()) {
                sortRecursively(n.getChildren(), cmp);
            }
        }
    }

    */
/** Sbtz → RuoYi 的 TreeSelect *//*

    private TreeSelect toTreeSelect(Sbtz n) {
        TreeSelect ts = new TreeSelect();
        ts.setId(n.getId());
        ts.setLabel(buildLabel(n));
        if (n.getChildren() != null && !n.getChildren().isEmpty()) {
            ts.setChildren(n.getChildren().stream().map(this::toTreeSelect).collect(Collectors.toList()));
        }
        return ts;
    }

    private String buildLabel(Sbtz n) {
        String name = n.getName() == null ? "" : n.getName();
        String code = n.getCode();
        return (code == null || code.isEmpty()) ? name : name + "(" + code + ")";
    }
    */
/*返回类似部门一样的数列表选择完毕*//*





    @Override
    public List<AssetNodeUsage> selectNodeUsageList(AssetNodeUsage nodeUsage){
        return sbtzMapper.selectDeptUsageList(nodeUsage);
    }

    @Override
    public List<AssetNodeUsage> selectNodeUsageById(Long nodeId) {
        if (nodeId == null) return Collections.emptyList();
        AssetNodeUsage q = new AssetNodeUsage();
        q.setAssetId(nodeId);            // 把路径里的 id 塞到查询对象
        // 需要的话可在这里塞 q.setOpenFlag(1) 只看占用中
        return sbtzMapper.selectNodeUsageById(q);
    }

}
*/
